﻿#include "softetherclient.h"
#include "appcommon.h"
#include "shell/shellutils.h"
#include "util/system_util.h"
#include <QApplication>
#include <QThread>

SoftEtherClient::SoftEtherClient() {
    m_vpncmdPath = AppCommon::getAppRootPath() + "/softether/vpncmd";
    m_vpnclientPath = AppCommon::getAppRootPath() + "/softether/vpnclient";
    m_connectOK = false;
}

void SoftEtherClient::run() {
    bool flag = false;
    int tryTimes = 0;
    do{
        tryTimes ++;

        clean();
        emit stateChanged(QString("连接VPN，第 %1 次尝试").arg(tryTimes));
        QThread::sleep(1);

        flag =startClient() && createNic(hubName) && enableNic(hubName) && createAccount(vlanName, serverAddress, hubName, username) && setPassword(vlanName, password) && disableRemote()
                && enableKeeplive() && enableAccountStartup(vlanName) && enableAccountRetry(vlanName) && setTcp(vlanName) && connectAccount(vlanName) && setLinkUp(vlanName) && setIP(vlanName, staticIP);
        if(flag){
            break;
        }

    }while(tryTimes<=3);

    if (!flag) {
        clean();
    } else {
        m_connectTime = QDateTime::currentDateTime();
    }
    m_connectOK = flag;
    emit loginFinish(flag);
}

void SoftEtherClient::connectVpn(QString serverAddress, QString hubName, QString username, QString password, QString staticIP) {
    this->vlanName = "vpn_" + hubName;
    this->hubName = hubName;
    this->serverAddress = serverAddress+"/tcp";
    this->username = username;
    this->password = password;
    this->staticIP = staticIP;
    start();
}

bool SoftEtherClient::isOnline() {
    return m_connectOK;
}

int SoftEtherClient::getOnlineTime() {
    return m_connectOK ? (m_connectTime.secsTo(QDateTime::currentDateTime())) : 0;
}

QString SoftEtherClient::getVpnIP() {
    cppc::NetInterfaceInfo vlanInfo = cppc::SystemUtil::getNetInterface(vlanName.toStdString());
    return QString::fromStdString(vlanInfo.ip);
}

bool SoftEtherClient::disconnectVpn(QString vlanName) {
    return runSoftEtherCmd("退出VPN登录", {"AccountDisconnect", vlanName});
}

bool SoftEtherClient::clean() {
    disconnectVpn(vlanName);
    deleteAccount(vlanName);
    disableNic(hubName);
    deleteNic(hubName);
    deleteLink(vlanName);

    stopClient();
}

bool SoftEtherClient::startClient() {
    QString step = "启动SoftEther Client";
    emit stateChanged(step);
    bool flag = ShellUtils::runCommand(m_vpnclientPath, {"start"}).success;

    emit stateChanged(step + (flag ? " [成功]" : "[失败]"));
    return flag;
}

bool SoftEtherClient::createNic(QString vlanName) {
    return runSoftEtherCmd("创建虚拟网卡", {"NicCreate", vlanName});
}

bool SoftEtherClient::enableNic(QString vlanName) {
    return runSoftEtherCmd("启用虚拟网卡", {"NicEnable", vlanName});
}

bool SoftEtherClient::createAccount(QString vlanName, QString serverAddress, QString hubName, QString username) {
    return runSoftEtherCmd("设置VPN账号", {"AccountCreate", vlanName, "/SERVER:" + serverAddress, "/HUB:" + hubName, "/USERNAME:" + username, "/NICNAME:" + vlanName});
}

bool SoftEtherClient::setPassword(QString vlanName, QString password) {
    return runSoftEtherCmd("设置VPN密码", {"AccountPasswordSet", vlanName, "/PASSWORD:" + password, "/TYPE:standard"});
}

bool SoftEtherClient::disableRemote() {
    return runSoftEtherCmd("禁用远程管理", {"RemoteDisable"});
}

bool SoftEtherClient::enableKeeplive() {
    return runSoftEtherCmd("启用保持连接", {"KeepEnable"});
}

bool SoftEtherClient::enableAccountStartup(QString vlanName) {
    return runSoftEtherCmd("设置自动启动", {"AccountStartupSet", vlanName});
}

bool SoftEtherClient::enableAccountRetry(QString vlanName) {
    return runSoftEtherCmd("设置自动重连", {"AccountRetrySet", vlanName, "/NUM:999", "/INTERVAL:5"});
}

bool SoftEtherClient::setIP(QString vlanName, QString staticIP) {
    QString stepTitle = "正在分配IP[" + vlanName+"]";
    emit stateChanged(stepTitle);
    bool flag = false;
    if (staticIP.isEmpty()) {
        flag = ShellUtils::runCommand("dhclient", {vlanName}).success;
    } else {
        flag = ShellUtils::runCommand("nmcli", {"con", "mod", vlanName, "ipv4.method", "manual", "ipv4.addresses", staticIP + "/16"}).success
               && ShellUtils::runCommand("nmcli", {"con", "up", vlanName}).success;
    }
    emit stateChanged(stepTitle + (flag ? " [成功]" : "[失败]"));
    return flag;
}

bool SoftEtherClient::setTcp(QString vlanName)
{
    return runSoftEtherCmd("设置TCP参数", {"AccountDetailSet", vlanName, "/MAXTCP:8","/INTERVAL:1", "/TTL:0", "/HALF:no", "/BRIDGE:no", "/MONITOR:no", "/NOTRACK:no", "/NOQOS:no"});
}

bool SoftEtherClient::connectAccount(QString vlanName) {
    return runSoftEtherCmd("登录账号", {"AccountConnect", vlanName});
}

bool SoftEtherClient::stopClient() {
    QString stepTitle = "停止SoftEther Client";
    emit stateChanged(stepTitle);
    bool flag = ShellUtils::runCommand("pkill", {"vpnclient"}).success;
    if (!flag) {
        bool processExists = ShellUtils::runCommand("pgrep", {"vpnclient"}).success;
        if (!processExists) {
            flag = true;
        }
    }
    emit stateChanged(stepTitle + (flag ? " [成功]" : "[失败]"));
    return flag;
}

bool SoftEtherClient::deleteAccount(QString vlanName) {
    return runSoftEtherCmd("设置自动启动", {"accountdelete", vlanName});
}

bool SoftEtherClient::disableNic(QString vlanName) {
    return runSoftEtherCmd("禁用虚拟网卡", {"nicdisable", vlanName});
}

bool SoftEtherClient::deleteNic(QString vlanName) {
    return runSoftEtherCmd("删除虚拟网卡", {"nicdelete", vlanName});
}

bool SoftEtherClient::setLinkUp(QString vlanName) {
    QString stepTitle = "启用网卡";
    emit stateChanged(stepTitle);
    ShellUtils::ShellResult ret = ShellUtils::runCommand("ip", {"link", "set", "dev", vlanName, "up"});
    emit stateChanged(stepTitle + (ret.success ? " [成功]" : "[失败-]" + ret.result));
    return ret.success;
}

bool SoftEtherClient::deleteLink(QString vlanName) {
    QString stepTitle = "清理网卡[" + vlanName+"]";
    emit stateChanged(stepTitle);
    bool flag = ShellUtils::runCommand("ip", {"link ", "delete", vlanName}).success;
    emit stateChanged(stepTitle + (flag ? " [成功]" : "[失败]"));
    return flag;
}

bool SoftEtherClient::runSoftEtherCmd(QString stepTitle, QStringList cmd) {
    emit stateChanged(stepTitle);
    QStringList args = {"localhost", "/CLIENT", "/CMD"};
    args << cmd;
    ShellUtils::ShellResult ret = ShellUtils::runCommand(m_vpncmdPath, args);
    emit stateChanged(stepTitle + (ret.success ? " [成功]" : "[失败-]" + ret.result));

    QApplication::processEvents();
    return ret.success;
}

QDateTime SoftEtherClient::getConnectTime() const {
    return m_connectTime;
}
